import Taro from '@tarojs/taro';
import { RequestOptions, RequestResult } from './base/interface';

export interface ClientOptions {
  // flora服务器地址，例如http://localhost:8080
  floraBaseURL: string;
  // 如果要创建多个不同的Client，区分不同client的标识符。有些全局变量需要区分（如localStorage）。默认为default.
  key?: string;
  // 是否是服务器端渲染。
  isServer?: boolean;
  // 是否开启开发状态，提供额外调试信息。
  isDev?: boolean;
  // 登录状态变化时调用的回调函数.
  onLoginStatusChanged?: () => void;
  onError?: () => void;
}

export type BaseApi = ReturnType<typeof createBaseApi>;

export function storageKey(options: ClientOptions, key: string): string {
  return `fl-${options.key}-${key}`;
}

const floraTokenKey = 'flora-login-token'
const floraLang = 'flora-lang'

export function createBaseApi(options: ClientOptions) {
  let lang = Taro.getStorageSync(floraLang)

  const clientOptions = options;

  function normalizeURL(path: string) {
    let url = path;
    if (!url.startsWith('http:') && !url.startsWith('https:')) {
      url = pathJoin([options.floraBaseURL, url]);
    }
    return url;
  }
  let currentToken: string = Taro.getStorageSync(floraTokenKey) || ''
  clientOptions.onLoginStatusChanged && clientOptions.onLoginStatusChanged();

  const request = async <T>(opts: RequestOptions): Promise<RequestResult<T>> => {
    let defaultHeader = {
      'Accept-Language': lang,
    };
    if (currentToken) {
      defaultHeader['Authorization'] = `Bearer ${currentToken}`;
    }
    return rawRequest<T>(Object.assign({}, opts, {
      url: normalizeURL(opts.url),
      header: Object.assign(defaultHeader, opts.header),
    })).then((r) => {
      if ('statusCode' in r && r.statusCode >= 400) {
        return { errorMsg: `Server error: ${r.data} (${r.statusCode})` };
      }
      if ('data' in r) {
        const data: T = r.data;
        return { data: data as T };
      }
      return { errorMsg: r.errMsg };
    }).catch((r) => {
      return { errorMsg: r.errMsg };
    });
  };

  const setLoginToken = async (token: string) => {
    currentToken = token;
    Taro.setStorageSync(floraTokenKey, token)
    clientOptions.onLoginStatusChanged && clientOptions.onLoginStatusChanged();
  }

  const getLoginToken = () => {
    return currentToken
  }

  const isDev = () => {
    if (clientOptions.isDev !== undefined) {
      return clientOptions.isDev;
    }
    return process.env.NODE_ENV === 'development';
  };


  const getLang = () => {
    return lang
  }

  const setLang = async (_lang: 'cn' | 'en') => {
    lang = _lang
    Taro.setStorageSync(floraLang, _lang)
  }

  return {
    request,
    setLoginToken,
    get isDev() {
      return isDev();
    },
    get loginToken() {
      return getLoginToken();
    },
    getLoginToken,
    isServer: clientOptions.isServer || false,
    get lang() {
      return getLang();
    },
    setLang,
  };
}

function pathJoin(pathArr: Array<string>): string {
  return pathArr.map(function (path) {
    if (path[0] === "/") {
      path = path.slice(1);
    }
    if (path[path.length - 1] === "/") {
      path = path.slice(0, path.length - 1);
    }
    return path;
  }).join("/");
}


function rawRequest<T>(opts: RequestOptions): Promise<{
  data: T,
  header: Record<string, string>,
  statusCode: number,
  errMsg: string,
} | { errMsg: string }> {
  return new Promise((resolve) => {
    Taro.request({
      url: opts.url,
      data: opts.data,
      header: opts.header,
      method: opts.method,
      success: (r) => {
        resolve({
          data: r.data,
          header: r.header,
          statusCode: r.statusCode,
          errMsg: r.errMsg,
        });
      },
      fail: (r) => {
        resolve({
          errMsg: r.errMsg,
        });
      }
    })
  });
}

